<template>
	<view class="rate-box" :class="[{animation},containerClass]" @touchmove="ontouchmove" @touchend="touchMoving=false">
		<view
			v-for="(val,i) in list" 
			:key="val" class="rate" 
			:style="{fontSize, paddingLeft: i!==0 ? rateMargin : 0, paddingRight: i<list.length-1 ? rateMargin : 0}"
			:class="[{scale: !disabled && val<=rateValue && animation && touchMoving,
						'ns-text-color':val<=rateValue,
						defaultColor:val>rateValue
				},`rate-${i}`,rateClass]" 
			:data-val="val"
			@click="onItemClick">
			<text class="iconfont icon-star"></text>
		</view>
	</view>
</template>

<script>
	import {
		getClientRect
	} from "./common";

	export default {
		name: 'sx-rate',
		props: {
			// 当前值
			value: {
				type: [Number,String],
			},
			// 最大星星数量
			max: {
				type: Number,
				default: 5
			},
			// 禁用
			disabled: {
				type: Boolean,
				default: false
			},
			// 动画效果
			animation: {
				type: Boolean,
				default: true
			},
			// 默认星星颜色
			defaultColor: {
				type: String,
				default: '#ccc'
			},
			// 滑选后星星颜色
			activeColor: {
				type: String,
				// default: '#FFB700'
			},
			// 星星大小
			fontSize: {
				type: String,
				default: 'inherit'
			},
			// 星星间距
			margin: {
				type: String,
				default: ''
			},
			// 自定义类名-容器
			containerClass: {
				type: String,
				default: ''
			},
			// 自定义类名-星星
			rateClass: {
				type: String,
				default: ''
			},
			index:{
				// 如果页面中存在多个该组件，通过该属性区分
				type: [Number, String],
			}
		},
		data() {
			return {
				rateValue: 0,
				touchMoving: false,
				startX: [],
				startW: 30
			}
		},
		computed: {
			list() {
				return [...new Array(this.max)].map((_, i) => i + 1)
			},
			rateMargin() {
				let margin = this.margin;
				if (!margin)
					return 0;

				switch (typeof margin) {
					case "number":
						margin += 'px';
					case "string":
						break;
					default:
						return 0;
				}

				let reg = /^(\d+)([^\d]*)/;
				let result = reg.exec(margin);
				if (!result)
					return 0;

				let [_, num, unit] = result;
				return num / 2 + unit;
			}
		},
		watch: {
			value: {
				handler(val) {
					this.rateValue = val;
				},
				immediate: true
			}
		},
		methods: {
			// 计算星星位置
			async initStartX() {
				let {
					max
				} = this;
				this.startX = [];

				for (let i = 0; i < max; i++) {

					let selector = `.rate-${i}`;
					let {
						left,
						width
					} = await getClientRect(selector, this);

					this.startX.push(left);
					this.startW = width;
				}
			},

			/**
			 * 手指滑动事件回调
			 * https://github.com/sunxi1997/uni-app-sx-rate/pull/1
			 * 原本的触摸处理在自定了样式后可能会出现bug, 已解决
			 */
			async ontouchmove(e) {
				if (!this.touchMoving) {
					this.touchMoving = true;
					// 开始手指滑动时重新计算星星位置,防止星星位置意外变化
					await this.initStartX();
				}

				let {
					startX,
					startW,
					max
				} = this;
				let {
					touches
				} = e;

				// 触摸焦点停留的位置
				let {
					pageX
				} = touches[touches.length - 1];


				// 超出最左边, 0 星
				if (pageX <= startX[0])
					return this.toggle(0);

				// 刚好在第一颗星
				else if (pageX <= startX[0] + startW)
					return this.toggle(1);

				// 超出最右边, 最大星
				else if (pageX >= startX[max - 1])
					return this.toggle(max);

				//计算星星停留的位置
				let startXHash = startX.concat(pageX).sort((a, b) => a - b);
				this.toggle(startXHash.indexOf(pageX));
			},
			// 点击回调
			onItemClick(e) {
				let {
					val
				} = e.currentTarget.dataset;
				this.toggle(val)
			},
			// 修改值
			toggle(val) {
				let {
					disabled
				} = this;
				if (disabled)
					return;
				if (this.rateValue !== val) {
					this.rateValue = val;
					this.$emit('update:value', val);
					let data={
						index:this.index,
						value:val
					}
					this.$emit('change', data)
				}
			}
		},
		mounted() {

		},
	}
</script>

<style scoped>
	@import "./sx-rate/iconfont.css";
</style>

<style lang="scss">
	.rate-box {
		min-height: 1.4em;
		display: flex;
		align-items: center;
	}

	.rate {
		display: inline-flex;
		justify-content: center;
		align-items: center;
		width: 1.2em;
		transition: all .15s linear;
	}

	.rate.scale {
		transform: scale(1.1);
	}
	
	.defaultColor{
		color: #ccc !important;
	}
	.activeColor{}
</style>
